package no.ntnu.item.arctis.runtime;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public abstract class SessionStateMachine extends IStateMachine {

	public SessionStateMachine(String sessionID, String parentSessionID) {
		super(sessionID, parentSessionID);
	}

	public abstract String getPartName();

	private SessionStateMachine parent;

	SessionStateMachine getParent() {
		return parent;
	}

	private Map<String, Set<SessionStateMachine>> sessions = new HashMap<String, Set<SessionStateMachine>>();

	Set<SessionStateMachine> getSessions(String partName) {
		return sessions.get(partName);
	}

	void addSession(SessionStateMachine session) {
		assert session != this;
		assert session.getPartName() != null;
		String partName = session.getPartName();
		if (!sessions.containsKey(partName))
			sessions.put(partName, new HashSet<SessionStateMachine>());
		sessions.get(partName).add(session);
		session.parent = this;
	}

	private void removeSession(SessionStateMachine session) {
		if (sessions.containsKey(session.getPartName())) {
			sessions.remove(session.getPartName());
		}
	}

	// TODO call destroy when state machine is destroyed
	public void destroy() {
		if (parent != null) {
			parent.removeSession(this);
		}
	}

	// TODO add positive and negative filters
	public Set<IStateMachine> select(String partName, boolean removeSelf, boolean one, String sessionID, String esmState) {

		Set<SessionStateMachine> s1 = sessions.get(partName);

		if (sessionID != null) {
			for (SessionStateMachine s : s1) {
				if (s.sessionID.equals(sessionID)) {
					Set<IStateMachine> selected = new HashSet<IStateMachine>();
					selected.add(s);
					return selected;
				}
				// error. no session with the given ID exists
			}
		} else {

			Set<IStateMachine> s2 = new HashSet<IStateMachine>();
			s2.addAll(s1);

			if (removeSelf) {
				s2.remove(this);
			}

			// filter according to ESM state

			if (one) {
				if (s2.size() > 1) {
					Set<IStateMachine> selected = new HashSet<IStateMachine>();
					selected.add(s2.iterator().next());
					return selected;
				} else if (s2.size() == 1) {
					return s2;
				} else {
					// error: no instance left
				}
			}

		}

		return Collections.emptySet();
	}

}
